#include <assert.h>
#include "parser.h"
#define PARSING_BLANKS "\t\r "
#define REDIRECTORS "<>"

/** 2 funciones privadas auxiliares **/
scommand * parse_scommand (Lexer * input, scommand * scmd);
scommand * parse_redirectors (Lexer * input, scommand * scmd);
/** **/

pipeline * parse_pipeline (Lexer * input)
{
	pipeline * result = NULL;
	scommand * scmd1 = NULL;
	scommand * scmd2 = NULL;
	bstring pipe = NULL;
	bstring esperar = NULL;
	bstring aux = NULL;	

	assert ( (input != NULL) && (!lexer_is_off (input)) );

	result = pipeline_new ();
	scmd1 = scommand_new (); 
	
	lexer_skip (input, PARSING_BLANKS);
	if (!lexer_is_off (input))
	{
		scmd1 = parse_scommand (input, scmd1);
	
		if (scmd1 != NULL) /* no hubo errores */
		{	
			pipeline_push_back (result, scmd1);

			/** tenemos que ver si hay 1 o 2 comandos **/
			/** para ello chequeamos si viene 1 | **/
			if (!lexer_is_off (input))
			{
				lexer_skip (input, PARSING_BLANKS);
				if (! lexer_is_off (input))
				{
					lexer_next (input, "|");
					pipe = lexer_item (input);
					if (biseqcstr (pipe, "|")) /** => debe haber 2 comandos **/
					{
						scmd2 = scommand_new ();
						scmd2 =  parse_scommand (input, scmd2);
						if (scmd2 != NULL && scommand_length (scmd2) > 0) /** => no hubo error **/
						{
							pipeline_push_back (result, scmd2);
							lexer_skip (input, PARSING_BLANKS);
							if (!lexer_is_off (input))
							{
								lexer_next (input, "&");
								esperar = lexer_item (input);
								if (biseqcstr (esperar, "&")) /**=> 2 cmdos sin wait**/
								{	
									pipeline_set_wait (result, false);
								}
								lexer_skip (input, PARSING_BLANKS);
								if (!lexer_is_off (input))
								{
									lexer_next_to (input, "\n");
									aux = lexer_item (input);
									if (!biseqcstr (aux, "")) /**=> error!: hay basura**/
									{
										pipeline_destroy (result);
										result = NULL;
									}
									bdestroy (aux);
								}
								bdestroy (esperar);
							}
						}
						else /** => error al parsear s2! **/
						{
							scommand_destroy (scmd2);
							scmd2 = NULL;
							pipeline_destroy (result);
							result = NULL;
						}		
					
					}
					else /** => no encontramos pipe. Es 1 solo cmdo **/
					{
						bdestroy (pipe); /** ya no la necesitamos **/
						lexer_next (input, "&");
						esperar = lexer_item (input);
						if (biseqcstr (esperar, "&")) /**=> 1 cmdo q no espera**/
						{
							pipeline_set_wait (result, false);
							lexer_skip (input, PARSING_BLANKS);
							if (!lexer_is_off (input))
							{
								lexer_next_to (input, "\n");
								aux = lexer_item (input);
								if (!biseqcstr (aux, "")) /**=> err: hay basura!**/
								{
									pipeline_destroy (result);
									result = NULL;
								}
								bdestroy (aux);
							}
						}
						else /** Ni | ni & => 1 solo cmdo q espera.Buscar basura**/
						{
							lexer_skip (input, PARSING_BLANKS);
							if (!lexer_is_off (input))
							{
								lexer_next_to (input, "\n");
								aux = lexer_item (input);
								if (!biseqcstr (aux, "")) /** => err: basura! **/
								{
									pipeline_destroy (result);
									result = NULL;
								}
									bdestroy (aux);
							}
						}
						bdestroy (esperar);
					}
				}
			}
		}
		else /** => error al parsear scmd1 **/
		{
			pipeline_destroy (result);
			result = NULL;
		}
	}
	return result;
}

scommand * parse_scommand (Lexer * input, scommand * scmd)
{
	bstring cmdo = NULL;
	bstring args = NULL;
	unsigned int i = 0;

	assert ( (!lexer_is_off (input)) && (input != NULL) && (scmd != NULL) );

	lexer_skip (input, PARSING_BLANKS);
	if (!lexer_is_off (input) )
	{
		lexer_next (input, ALPHANUMERIC);
		cmdo = lexer_item (input);
		if (blength (cmdo) > 0)
		{
			scommand_push_back (scmd, cmdo);

			args = cmdo;
			while ( (!lexer_is_off (input)) && (!biseqcstr (args, "")) )
			{
				if (i>0) /** la primera vez no, todavia no lei args **/
				{
					scommand_push_back (scmd, args);
				}
			
				lexer_skip (input, PARSING_BLANKS);
				if (!lexer_is_off (input))
				{
					lexer_next (input, ALPHANUMERIC "-~*._=/");
					args = lexer_item (input);
				}
				i += 1;
			}
			if (!lexer_is_off (input))
			{
				lexer_skip (input, PARSING_BLANKS);
				scmd = parse_redirectors (input, scmd);
			}
		}
	}
	return scmd;
}

scommand * parse_redirectors (Lexer * input, scommand * scmd)
{
	bstring redir = NULL;
	bstring redir_in = NULL;
	bstring redir_out = NULL;

	assert ( (input != NULL) && (!lexer_is_off (input)) && (scmd != NULL) );

	lexer_skip (input, PARSING_BLANKS);
	if (!lexer_is_off (input))
	{
		lexer_next (input, REDIRECTORS);
		redir = lexer_item (input);
		if (biseqcstr (redir, "<")) /** tenemos 1º el redirector de entrada **/
		{
			lexer_skip (input, PARSING_BLANKS);
			if (!lexer_is_off (input))
			{
				lexer_next (input, ALPHANUMERIC "/*.~-_");
				redir_in = lexer_item (input);
				if (biseqcstr (redir_in, "")) /**=> error:falta nom archivo!**/
				{
					bdestroy (redir_in);
					scommand_destroy (scmd);
					scmd = NULL;
				}
				else /** => todo bien! **/
				{
					scommand_set_redir_in (scmd, redir_in);
					bdestroy (redir);
					/** ahora buscamos si hay redirector de salida **/
					lexer_skip (input, PARSING_BLANKS);
					if (!lexer_is_off (input))
					{
						lexer_next (input, ">");
						redir = lexer_item (input);
						if (biseqcstr (redir, ">")) /**=> hay salida**/
						{
							lexer_skip (input, PARSING_BLANKS);
							if (!lexer_is_off (input))
							{
								lexer_next (input, ALPHANUMERIC "*/.~-_");
								redir_out = lexer_item (input);
								if (biseqcstr (redir_out, "")) /**error! **/
								{
									bdestroy (redir_out);
									scommand_destroy (scmd);
									scmd = NULL;
								}
								else /** todo bien! **/
								{
									scommand_set_redir_out (scmd, redir_out);
									bdestroy (redir);
								}
							} 
							else /** error: falta nombre salida! **/
							{
								bdestroy (redir);
								scommand_destroy(scmd);
								scmd = NULL;
							}
						}
						else /** no pasa nada, no hay salida **/
						{
							bdestroy(redir);
						}
					}
				}
			}
			else /** error: falta nombre entrada! **/	
			{
				bdestroy (redir);
				scommand_destroy (scmd);
				scmd = NULL;
			}
		}
		else if (biseqcstr (redir, ">")) /** tenemos primero el de salida **/
		{
			lexer_skip (input, PARSING_BLANKS);
			if (!lexer_is_off (input))
			{
				lexer_next (input, ALPHANUMERIC ".-_");
				redir_out = lexer_item (input);
				if (biseqcstr (redir_out, "")) /**=> error: falta nombre! **/
				{
					bdestroy (redir);
					scommand_destroy(scmd);
					scmd = NULL;
				}
				else /** hay nombre! **/
				{
					scommand_set_redir_out (scmd, redir_out);
					bdestroy (redir);
					/** buscamos a ver si hay redirector de entrada **/
					lexer_skip (input, PARSING_BLANKS);
					if (!lexer_is_off (input))
					{
						lexer_next (input, "<");
						redir = lexer_item (input);
						if (biseqcstr (redir, "<"))
						{
							lexer_skip (input, PARSING_BLANKS);
							if (!lexer_is_off (input))
							{
								lexer_next (input, ALPHANUMERIC "-_.");
								redir_in = lexer_item (input);
								if (biseqcstr (redir_in, "")) /**error!**/
								{
									bdestroy (redir_in);
									bdestroy (redir);
									scommand_destroy (scmd);
									scmd = NULL;
								}
								else
								{
									scommand_set_redir_in (scmd, redir_in);
									bdestroy (redir);
								}
							}
							else /**error: falta nombre entrada!**/
							{
								bdestroy(redir);
								scommand_destroy (scmd);
								scmd = NULL;
							}
						}
					}
				}
			}
			else /**error: falta nombre salida! **/ 
			{
				bdestroy (redir);
				scommand_destroy(scmd);
				scmd = NULL;
			}
		} /**todo bien, simplemente no hay redirectores **/
	}
	return scmd;
}
